package com.company.finance.ddd.domain.core.bill.aggregate;

import com.company.finance.ddd.domain.core.bill.aggregate.assembler.*;
import com.company.finance.ddd.domain.core.bill.enums.BillSubTypeEnum;
import com.company.finance.ddd.domain.core.voucher.aggregate.Voucher;
import com.company.finance.ddd.domain.core.voucher.rule.BillItemRule;
import lombok.Builder;

import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 本类通过反射方式获取bill的明细表(以Item为后缀)对应的装配类{@link ItemAssembler}，
 * bill的SUB_TYPE_CODE与Assembler的映射关系见{@link BillSubTypeMapper}。
 * @author wanglei
 */
@Builder
class ItemAssemblerDispatcher {

    private static final Map<String, ItemAssembler> ASSEMBLER_CACHE = new ConcurrentHashMap<>();

    private final BillItemRule billItemRule;
    private final BillAggregate billAggregate;

    List<Voucher.VoucherItem> dispatch() {
        char[] classPrefixName = BillSubTypeMapper
                .getClassPrefixName(BillSubTypeEnum.getBillSubTypeEnum(billAggregate.getBill().getSUB_TYPE_CODE())).toCharArray();
        Arrays.fill(classPrefixName, 0, 1, (char) (classPrefixName[0] - 32));
        String fullName = MessageFormat.format("{0}.{1}ItemAssembler", ItemAssembler.class.getPackage().getName()
                        , new String(classPrefixName));
        ItemAssembler itemAssembler = ASSEMBLER_CACHE.get(fullName);
        if (null != itemAssembler) {
            return itemAssembler.assemble(billItemRule, billAggregate);
        }
        try {
            itemAssembler = ((ItemAssembler)Class.forName(fullName).newInstance());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        ASSEMBLER_CACHE.putIfAbsent(fullName, itemAssembler);
        return itemAssembler.assemble(billItemRule, billAggregate);
    }
}
